package com.yanx.common.core.domain.entity;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.yanx.common.exception.BusinessException;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author gotanks
 * @create 2022/4/28
 */
public interface IBaseEntity<ID extends Serializable> extends Serializable {

    ID getId();

    void setId(ID id);

//    ID generateId();

    /**
     * 添加对象到List中，id相同则更新
     *
     * @param subEntity 需要添加的子表对象
     * @param <T>       继承BaseEntity的泛型
     */
    default <T extends IBaseEntity<ID>> void addList(T subEntity) {
        addList(subEntity, null);
    }

    /**
     * 添加对象到List中，id相同则更新
     *
     * @param subEntity         需要添加的子表对象
     * @param deepCloneConsumer 自定义实现深拷贝
     * @param <T>               继承BaseEntity的泛型
     */
    default <T extends IBaseEntity<ID>> void addList(T subEntity, Consumer<? super T> deepCloneConsumer) {
        Field field = this.findListField(subEntity.getClass()).orElseThrow(BusinessException::new);
        List<T> tList = this.findListFieldValue(field);
        ID id = subEntity.getId();
//        //自己生成ID，便于获取
//        if (id == null) {
//            subEntity.setId(this.generateId());
//        }
        if (tList.stream().noneMatch(s -> s.getId().equals(id))) {
            tList.add(subEntity);
        } else {
            if (deepCloneConsumer == null) {
                deepCloneConsumer = s -> copyPropertiesIgnoreNull(subEntity, s);
            }
            tList.stream().filter(s -> s.getId().equals(id)).findFirst().ifPresent(deepCloneConsumer);
        }
    }

    /**
     * 从list属性中移除一条记录
     *
     * @param id 要删除的对象id
     */
    default void removeList(Long id) {
        for (Field field : this.findListFields()) {
            this.findListFieldValue(field).removeIf(f -> f.getId().equals(id));
        }
    }

    /**
     * 从list属性中移除一条记录，指定类型
     *
     * @param id  id 要删除的对象id
     * @param clz id 要删除的对象类型
     * @param <T> 继承BaseEntity的泛型
     */
    default <T extends IBaseEntity<ID>> void removeList(Long id, Class<T> clz) {
        this.findListField(clz).ifPresent(field -> this.findListFieldValue(field).removeIf(f -> f.getId().equals(id)));
    }

    /**
     * 从list属性中获取一条记录
     *
     * @param id 要获取的对象id
     */
    default <T extends IBaseEntity<ID>> T findList(Long id) {
        for (Field field : this.findListFields()) {
            List<T> list = this.findListFieldValue(field);
            for (T t : list) {
                if (t.getId().equals(id)) {
                    return t;
                }
            }
        }
        return null;
    }

    /**
     * 获取参数对象相关的属性值
     *
     * @param field 字段
     * @param <T>   继承BaseEntity的泛型
     * @return 对象值（List类型）
     */
    default <T extends IBaseEntity<ID>> List<T> findListFieldValue(Field field) {
        // 先不抛出异常
        List<T> tList = null;
        try {
            // 调用get方法
            String upperCaseFirstWord = upperCaseFirstWord(field.getName());
            String getMethodName = "get" + upperCaseFirstWord;
            Method getMethod = this.getClass().getMethod(getMethodName);
            Object result = getMethod.invoke(this);
            if (result == null) {
                tList = new ArrayList<>();
                // 调用set方法
                String setMethodName = "set" + upperCaseFirstWord;
                Method setMethod = this.getClass().getMethod(setMethodName, List.class);
                setMethod.invoke(this, tList);
            } else {
                tList = (List<T>) result;
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return tList;
    }

    /**
     * 获取参数对象相关的属性字段
     *
     * @param tClass 指定List的类型
     * @return 返回指定类型的字段
     */
    default Optional<Field> findListField(Class<? extends IBaseEntity> tClass) {
        return this.findListFields().stream()
                .filter(f -> f.getGenericType().getTypeName().contains(tClass.getTypeName()))
                .findFirst();
    }

    /**
     * 获取所有List字段
     *
     * @return 返回所有list字段集合
     */
    default List<Field> findListFields() {
        return Arrays.stream(this.getClass().getDeclaredFields())
                .filter(f -> f.getType() == List.class)
                .filter(f -> f.getGenericType() instanceof ParameterizedType)
                .peek(f -> f.setAccessible(true))
                .collect(Collectors.toList());
    }

    /**
     * 首字母大写
     *
     * @param str 需要处理的字符串
     * @return 首字母大写的字符串
     */
    static String upperCaseFirstWord(String str) {
        char[] ch = str.toCharArray();
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }

    static void copyPropertiesIgnoreNull(Object source, Object target) {
        BeanUtil.copyProperties(source, target, CopyOptions.create().setIgnoreNullValue(true));
    }
}
